package team.seekers.hula.course.resource.examSubmit.service;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import team.seekers.hula.common.entity.result.ApiExceptionEnum;
import team.seekers.hula.common.utils.AssertUtils;
import team.seekers.hula.common.utils.BaseConvertUtils;
import team.seekers.hula.course.courseUser.service.CourseUserService;
import team.seekers.hula.course.resource.exam.entity.dto.ExamProblemDTO;
import team.seekers.hula.course.resource.exam.entity.dto.ExamQueryDTO;
import team.seekers.hula.course.resource.exam.service.ExamService;
import team.seekers.hula.course.resource.examSubmit.dao.ExamRecordDao;
import team.seekers.hula.course.resource.examSubmit.entity.dao.ExamRecordDO;
import team.seekers.hula.course.resource.examSubmit.entity.dto.ExamRecordCreateDTO;
import team.seekers.hula.course.resource.examSubmit.entity.dto.ExamRecordDTO;
import team.seekers.hula.course.resource.examSubmit.entity.dto.ProblemSubmission;
import team.seekers.hula.course.resource.examSubmit.entity.vo.ExamRecordInfoVO;
import team.seekers.hula.course.resource.examSubmit.entity.vo.ProblemSubmissionListVO;
import team.seekers.hula.course.resource.problem.entity.dto.ProblemDTO;
import team.seekers.hula.course.resource.problem.service.ProblemService;
import team.seekers.hula.course.resource.problemSubmit.entity.dto.SubmissionDTO;
import team.seekers.hula.course.resource.problemSubmit.service.SubmissionService;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * date: 2022/5/9 11:29
 *
 * @author GH
 * QQ 1124813753
 */
@Service
public class ExamRecordService {

    @Autowired
    private ExamRecordDao examRecordDao;

    @Autowired
    private ExamService examService;

    @Autowired
    private SubmissionService submissionService;

    @Autowired
    private ProblemService problemService;

    @Autowired
    private CourseUserService courseUserService;



    @Transactional(rollbackFor = Exception.class)
    public String participateExam(String examId, String userId,String realIp) {
        ExamQueryDTO examQueryDTO = examService.queryById(examId);

        // 生成一次空白的提交
        List<ExamProblemDTO> problems = examQueryDTO.getProblems();
        ArrayList<String> problemIds = new ArrayList<>();
        for (ExamProblemDTO problem : problems) {
            problemIds.add(problem.getId());
        }
        // 远端获取problem信息
        Map<String, ProblemDTO> problemDtoMap = problemService.idsMapDTO(problemIds);

        Map<String, ExamProblemDTO> problemCriteriaMap = examService.idToProblemDTOMap(examId);


        List<ProblemSubmission> problemSubmissions= new ArrayList<>();
        for (ExamProblemDTO problem : problems) {
            ProblemDTO problemDTO = problemDtoMap.get(problem.getId());
            ProblemSubmission problemSubmission = new ProblemSubmission();
            problemSubmission.setProblemId(problemDTO.getId());
            problemSubmission.setOptions(problemDTO.getOptions());
            problemSubmission.setRightAnswer("0");
            problemSubmission.setProblemType(problemDTO.getType());
            problemSubmission.setCriteria(problemCriteriaMap.get(problem.getId()).getCriteria());

            if(problemDTO.getType() == 2){
                problemSubmission.setAnswer("");
            }

            problemSubmissions.add(problemSubmission);
        }


        // 初始化的时候不提交
//        List<SubmissionDTO> submissions = problemSubmissions.stream().map(pSubmit ->
//                SubmissionDTO.builder()
//                        .pId(pSubmit.getProblemId())
//                        .uId(userId)
//                        .exId(examId)
//                        .ipv4(realIp)
//                        .result(pSubmit.getSubmitRes())
//                        .score(SubmissionDTO.judge(pSubmit.getAnswer(), pSubmit.getCriteria(), pSubmit.getSubmitRes(), pSubmit.getProblemType()))
//                        .build()
//        ).collect(Collectors.toList());
//        submissionClient.saveOrUpdateBatch(submissions);


        Integer count = examRecordDao.lambdaQuery()
                .eq(ExamRecordDO::getExamId, examId)
                .eq(ExamRecordDO::getUserId, userId)
                .count();
        ExamRecordDO examRecordDO = ExamRecordDO.builder()
                .examId(examId)
                .userId(userId)
                .count(count+1)
                .submissions(BaseConvertUtils.objectListToBytes(problemSubmissions))
                .build();
        examRecordDao.save(examRecordDO);
        return examRecordDO.getId();
    }

    @Transactional(rollbackFor = Exception.class)
    public void examSubmit(ExamRecordCreateDTO createDTO) {
        ExamRecordDO examRecordDO = examRecordDao.getById(createDTO.getExamRecordId());

        ArrayList<String> problemIds = new ArrayList<>();
        for (ProblemSubmission submission : createDTO.getSubmissions()) {
            problemIds.add(submission.getProblemId());
        }

        // 远端获取problem信息
        Map<String, ProblemDTO> problemDtoMap = problemService.idsMapDTO(problemIds);

        Map<String, ExamProblemDTO> problemCriteriaMap = examService.idToProblemDTOMap(examRecordDO.getExamId());
        for (ProblemSubmission submission : createDTO.getSubmissions()) {
            ProblemDTO problemDTO = problemDtoMap.get(submission.getProblemId());
            submission.setOptions(problemDTO.getOptions());
            submission.setRightAnswer(problemDTO.getAnswer());
            submission.setProblemType(problemDTO.getType());
            submission.setCriteria(problemCriteriaMap.get(submission.getProblemId()).getCriteria());
            submission.setScore(SubmissionDTO.judge(submission.getRightAnswer(), submission.getCriteria(), submission.getAnswer(), submission.getProblemType()));
        }


        List<SubmissionDTO> submissions = createDTO.getSubmissions().stream().map(pSubmit ->
                SubmissionDTO.builder()
                        .pId(pSubmit.getProblemId())
                        .uId(examRecordDO.getUserId())
                        .exId(examRecordDO.getExamId())
                        .ipv4(createDTO.getIpv4())
                        .result(pSubmit.getAnswer())
                        .score(pSubmit.getScore())
                        .build()
        ).collect(Collectors.toList());

//        submissionService.saveOrUpdateBatch(submissions);
        examRecordDO.setSubmissions(BaseConvertUtils.objectListToBytes(createDTO.getSubmissions()));

        Double score = submissions.stream().mapToDouble(SubmissionDTO::getScore).sum();
        examRecordDO.setScore(score.floatValue());

        examRecordDO.setStatus(1);
        examRecordDao.updateById(examRecordDO);
    }

    /**
     * 查询测试提交记录
     */
    public List<ExamRecordDTO> list(String examId, String userId) {


        List<ExamRecordDO> examRecordDOList = examRecordDao.lambdaQuery().select(
                        ExamRecordDO::getId,
                        ExamRecordDO::getExamId,
                        ExamRecordDO::getScore,
                        ExamRecordDO::getStatus,
                        ExamRecordDO::getSubmissions,
                        ExamRecordDO::getGmtCreate
                ).eq(ExamRecordDO::getExamId, examId)
                .eq(ExamRecordDO::getUserId, userId)
                .orderByAsc(ExamRecordDO::getGmtCreate).list();

        for (ExamRecordDO examRecordDO : examRecordDOList) {
            // 获取考试相关信息
            ExamQueryDTO examQueryDTO = examService.queryById(examRecordDO.getExamId());
            Date now = new Date();
            long lastSeconds = examQueryDTO.getLimitDuration()*60 - (now.getTime() - examRecordDO.getGmtCreate().getTime())/1000;
            if(lastSeconds < 0 && examRecordDO.getStatus() == 0){
                // 已截止
                examRecordDO.setStatus(1);
                examRecordDao.updateById(examRecordDO);
            }
        }


        return ExamRecordDO.toDTOList(examRecordDOList);
    }

    /**
     * 查询某个测试的某次提交的所有题目提交
     */
    public List<ProblemSubmission> queryExamSubmission(Long examRecordId) {
        ExamRecordDO examRecordDO = examRecordDao.lambdaQuery()
                .select(ExamRecordDO::getSubmissions)
                .eq(ExamRecordDO::getId, examRecordId)
                .one();
        AssertUtils.notNull(examRecordDO, ApiExceptionEnum.DB_FAIL);
        return BaseConvertUtils.bytesToObjectList(examRecordDO.getSubmissions());
    }


    public ExamRecordInfoVO queryExamRecordInfo(String examRecordId) {
        ExamRecordDO examRecordDO = examRecordDao.lambdaQuery()
                .select(
                        ExamRecordDO::getId,
                        ExamRecordDO::getExamId,
                        ExamRecordDO::getCount,
                        ExamRecordDO::getScore,
                        ExamRecordDO::getGmtCreate,
                        ExamRecordDO::getStatus,
                        ExamRecordDO::getSubmissions
                )
                .eq(ExamRecordDO::getId, examRecordId)
                .one();
        AssertUtils.notNull(examRecordDO, ApiExceptionEnum.DB_FAIL);

        // 获取考试相关信息
        ExamQueryDTO examQueryDTO = examService.queryById(examRecordDO.getExamId());
        Date now = new Date();
        long lastSeconds = examQueryDTO.getLimitDuration()*60 - (now.getTime() - examRecordDO.getGmtCreate().getTime())/1000;
        if(lastSeconds < 0 && examRecordDO.getStatus() == 0){
            // 已截止
            examRecordDO.setStatus(1);
            if(now.getTime() > examQueryDTO.getGmtEnd().getTime()){
                // 已结束
                examRecordDO.setStatus(2);
            }
            examRecordDao.updateById(examRecordDO);
        }


        ExamRecordInfoVO examRecordInfoVO = new ExamRecordInfoVO();
        BeanUtils.copyProperties(examRecordDO,examRecordInfoVO);
        examRecordInfoVO.setLastSeconds(lastSeconds);
        examRecordInfoVO.setExamTitle(examQueryDTO.getTitle());
        examRecordInfoVO.setExamDescription(examQueryDTO.getDescription());
        examRecordInfoVO.setCriteria(examQueryDTO.getTotalScore());

        List<ProblemSubmission> problemSubmission = BaseConvertUtils.bytesToObjectList(examRecordDO.getSubmissions());
        // 增补转换题目信息
        ArrayList<String> problemIds = new ArrayList<>();
        for (ProblemSubmission submission : problemSubmission) {
            problemIds.add(submission.getProblemId());
        }
        // 远端获取problem信息
        Map<String, ProblemDTO> problemDtoMap = problemService.idsMapDTO(problemIds);

        ArrayList<ProblemSubmissionListVO> problemSubmissionListVOS = new ArrayList<>();
        for (ProblemSubmission submission : problemSubmission) {
            ProblemSubmissionListVO problemSubmissionListVO = ProblemSubmissionListVO.builder()
                    .problemId(submission.getProblemId())
                    .answer(submission.getAnswer())
                    .rightAnswer(submission.getRightAnswer())
                    .score(submission.getScore())
                    .criteria(submission.getCriteria())
                    .problemType(submission.getProblemType())
                    .problemDescription(problemDtoMap.get(submission.getProblemId()).getDescription())
                    .options(submission.getOptions()).build();
            problemSubmissionListVOS.add(problemSubmissionListVO);
        }
        examRecordInfoVO.setSubmissions(problemSubmissionListVOS);
        return examRecordInfoVO;
    }

    /**
     * 修改题目提交
     */
    public void updateSubmit(List<SubmissionDTO> submission) {
        submissionService.saveOrUpdateBatch(submission);
    }
}
